/*
 * Copyright 2006-2008 Michele Mostarda ( michele.mostarda@gmail.com ).
 * All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.graphnav.swing;

import org.graphnav.swing.event.EditingListener;

import javax.swing.JOptionPane;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;

/**
 * Default implementation of a <i>Node</i>.
 */
public class DefaultNode extends Node {

    /**
     * Size of the collapse button.
     */
    public static final double COLLAPSE_BUTTON_SQUARE = 5.0d;

    /**
     *
     */
    public static long counter = 0;

    /**
     * Medium level node dimension.
     */
    protected static final Dimension DIMENSION_LEVEL_MEDIUM  = new Dimension(70, 20);

    /**
     * Minimal level node dimension.
     */
    protected static final Dimension DIMENSION_LEVEL_MINIMAL = new Dimension(20, 20);

    /**
     * Node internal text border size.
     */
    protected static final int TEXT_BORDER = 5;

    private static final DefaultNodeRenderableEditor renderableEditor = new DefaultNodeRenderableEditor();

    /**
     * Node description.
     */
    private String description;

    /**
     * Node position.
     */
    private Point position;

    /**
     * Node bounds.
     */
    private Rectangle bounds = new Rectangle();

    protected static DefaultNodeRenderableEditor getDefaultNodeRenderableEditor() {
        return renderableEditor;
    }

    /**
     * Constructor.
     *
     * @param description
     * @param position
     */
    public DefaultNode(String description, Point position) {
        this.description = description;
        this.position    = new Point(position);
    }

    /**
     * Constructor.
     *
     * @param position
     */
    public DefaultNode(Point position) {
        this( "node_" + counter++, position);
    }

    /**
     * Constructor.
     *
     * @param description
     */
    public DefaultNode(String description) {
        this(description, new Point(0, 0));
    }

    /**
     * Returns the node bounds.
     * 
     * @param detailLevel
     * @return
     */
    public Rectangle2D getBounds2D(int detailLevel) {
        bounds.setLocation(position);
        bounds.setSize(
                detailLevel == DETAIL_LEVEL_MINIMAL ? DIMENSION_LEVEL_MINIMAL : DIMENSION_LEVEL_MEDIUM
        );
        return bounds;
    }

    protected void setDescription(String d) {
        description = d;
    }

    public String getDescription() {
        return description;
    }

    public void move(int dx, int dy) {
        position.translate(dx, dy);
    }

    public void setLocation(int x, int y) {
        position.setLocation(x,y);
    }

    public void paintNode(Graphics2D g2din, boolean selected, boolean overlapped, int detailLevel) {
        Graphics2D g2d = getGraphics2D(g2din, detailLevel);

        if(detailLevel == DETAIL_LEVEL_MEDIUM) {

            //Fill node.
            Rectangle2D currBounds = getBounds2D(DETAIL_LEVEL_MEDIUM);

            RoundRectangle2D roundRect = new RoundRectangle2D.Double(
                    currBounds.getX(),
                    currBounds.getY(),
                    currBounds.getWidth(),
                    currBounds.getHeight(),
                    Renderable.ROUND_ARCHW,
                    Renderable.ROUND_ARCH
            );

//            Rectangle2D rect = new Rectangle2D.Double(
//                    currBounds.getX(),
//                    currBounds.getY(),
//                    currBounds.getWidth(),
//                    currBounds.getHeight()
//            );

            g2d.setColor(selected ? Color.RED : Color.GREEN);
            g2d.fill(roundRect);

            //Draw border.
            g2d.setColor( overlapped  ? Color.BLUE  : Color.BLACK);
            g2d.setStroke( overlapped ? THICK_STROKE : THIN_STROKE);
            g2d.draw(roundRect);

            //Draw text.
            g2d.drawString(
                    getDescription(),
                    (int)  currBounds.getX() + TEXT_BORDER,
                    (int) (currBounds.getY() + currBounds.getHeight() - TEXT_BORDER)
            );
        } else {

            Rectangle2D miminalBounds = getBounds2D(DETAIL_LEVEL_MINIMAL);
            RoundRectangle2D roundRect = new RoundRectangle2D.Double(
                miminalBounds.getX(),
                miminalBounds.getY(),
                miminalBounds.getWidth(),
                miminalBounds.getHeight(),
                Renderable.ROUND_ARCHW,
                Renderable.ROUND_ARCH
            );
            g2d.setColor(selected ? Color.RED : Color.GREEN);
            g2d.fill( roundRect );
            g2d.setColor(overlapped  ? Color.BLACK  : Color.BLUE);
            g2d.draw( roundRect );

        }
    }

    public void editNewArc(Node toNode, EditingListener el) {
        String name = JOptionPane.showInputDialog("Arc name?");
        if(name != null) {
            el.addArcRequired(this, toNode, name);
        }
    }

    public RenderableEditor edit(EditingListener el) {
        DefaultNodeRenderableEditor re = getDefaultNodeRenderableEditor();
        re.configure(this, el);
        return re;
    }

}
